home *** CD-ROM | disk | FTP | other *** search
/ Java Developer's Companion / Java Developer's Companion.iso / Javacup / PR8ADPL7.TAR / productivity_tools / PR8ADPL7 / FileSystem.java < prev    next >
Encoding:
Java Source  |  1996-05-23  |  21.1 KB  |  756 lines

  1. // FileSystem.java
  2. // A static class containing functions for accessing the filesystem
  3. import java.io.*;
  4. import java.util.Vector;
  5. import java.util.StringTokenizer;
  6. import JFSdirectory;
  7. import JFSuser;
  8. import LineInputStream;
  9. import LineOutputStream;
  10.  
  11. public class FileSystem
  12. {
  13.     static String root = ".";    // root dir of JFS
  14.     static JFSfile rootfile;    // info about root directory
  15.     static LineOutputStream db = new NullOutputStream();
  16.  
  17.     // init
  18.     // Set the root directory and create the root fileinfo
  19.     static void init(String r)
  20.     {
  21.     root = r;
  22.     rootfile = new JFSfile();
  23.         rootfile.name = "";
  24.         rootfile.type = "jfs/directory";
  25.         rootfile.multiversion = false;
  26.         JFSversion rootver = new JFSversion();
  27.         rootver.number = 1;
  28.         rootver.creator = "root";
  29.         rootver.time = 0;
  30.     rootver.size = 0;
  31.         JFSfileuser rootusr = new JFSfileuser();
  32.         rootusr.name = "all";
  33.         rootusr.rwp = "r";
  34.         rootfile.versions.addElement(rootver);
  35.         rootfile.users.addElement(rootusr);
  36.     }
  37.  
  38.     // simplify
  39.     // Turn a path like //foo///bar/ to /foo/bar
  40.     static String simplify(String s) throws BadPathException
  41.     {
  42.     if (s.length() == 0 || s.charAt(0) != '/')
  43.         throw new BadPathException("Missing / at start of filename");
  44.     if (s.indexOf(',') != -1)
  45.         throw new BadPathException("Filename contains a ,");
  46.     StringTokenizer tok = new StringTokenizer(s,"/");
  47.     if (tok.countTokens() == 0)
  48.         return "/";    // string only contains /'s
  49.     String sim = "";
  50.     while(tok.hasMoreTokens()) {
  51.         String bit = tok.nextToken();
  52.         if (bit.charAt(0) == '.')
  53.             throw new BadPathException("Path component starts "+
  54.                            "with a .");
  55.         sim += "/"+bit;
  56.         }
  57.     return sim;
  58.     }
  59.  
  60.     // parent
  61.     // Returns the parent directory from the given string, or an empty
  62.     // string for /
  63.     static String parent(String d) throws BadPathException
  64.     {
  65.     String dir = simplify(d);
  66.     if (dir.equals("/"))
  67.         return "";
  68.     return simplify(dir.substring(0, dir.lastIndexOf('/')+1));
  69.     }
  70.  
  71.     // statfile
  72.     // Return the JFSfile structure for a given filename
  73.     static synchronized JFSfile statfile(String s)
  74.         throws BadPathException
  75.     {
  76.     db.puts("statfile("+s+")");
  77.     String fn = simplify(s);
  78.     if (fn.equals("/"))
  79.         return rootfile;
  80.     else {
  81.         // Get the directory in which this file lies
  82.         String par = parent(fn);
  83.         JFSdirectory dir = getdir(par);
  84.         JFSfile entry = dir.find(fn.substring(fn.lastIndexOf('/')+1));
  85.         if (entry == null)
  86.             throw new BadPathException(s+" not found");
  87.         else
  88.             return entry;
  89.         }
  90.     }
  91.  
  92.     // getdir
  93.     // Returns the JFSdirectory structure for a given filename (which
  94.     // must be a directory). Because the size field is not
  95.     // stored in the .jfs file, it must be filled in here.
  96.     static synchronized JFSdirectory getdir(String s)
  97.         throws BadPathException
  98.     {
  99.     db.puts("getdir("+s+")");
  100.     String path = simplify(s);
  101.     String jfspath = root+path+"/.jfs";
  102.     JFSdirectory dir;
  103.     try {
  104.         LineInputStream jfs = new LineInputStream(
  105.                     new FileInputStream(jfspath));
  106.         dir = new JFSdirectory(jfs);
  107.         jfs.close();
  108.         }
  109.     catch(FileNotFoundException e)
  110.         throw new BadPathException("Couldn't find .jfs file "+jfspath);
  111.     catch(IOException e)
  112.         throw new BadPathException("Error reading .jfs file "+jfspath+
  113.                        " : "+e.getMessage());
  114.  
  115.     // Get the actual size of every file in the directory, from the
  116.     // local filesystem.
  117.     boolean writeout = false;
  118.     for(int i=0; i<dir.size(); i++) {
  119.         JFSfile entry = dir.find(i);
  120.         String full = root+path+"/"+entry.name;
  121.         for(int j=0; j<entry.versions.size(); j++) {
  122.             JFSversion v = (JFSversion)entry.versions.elementAt(j);
  123.             String fullver = full;
  124.             if (entry.multiversion)
  125.                 fullver += ","+String.valueOf(v.number);
  126.             File stat = new File(fullver);
  127.             if (!stat.exists()) {
  128.                 // oh no! The local file for this version has
  129.                 // been deleted. 
  130.                 writeout = true;
  131.                 if (entry.multiversion) {
  132.                     // Just remove a version
  133.                     entry.versions.removeElementAt(j--);
  134.                     continue;
  135.                     }
  136.                 else {
  137.                     // Remove the whole file
  138.                     dir.delete(i--);
  139.                     break;
  140.                     }
  141.                 }
  142.             if (stat.isDirectory())
  143.                 v.size = 0;
  144.             else
  145.                 v.size = stat.length();
  146.             }
  147.         }
  148.  
  149.     if (writeout) {
  150.         // Because some local files have been deleted, we need to
  151.         // write out this directory again.
  152.         putdir(dir, path);
  153.         }
  154.     return dir;
  155.     }
  156.  
  157.     // getuser
  158.     // Lookup and return a JFSuser structure from the /etc/users file
  159.     static synchronized JFSuser getuser(String name)
  160.         throws BadUserException
  161.     {
  162.     LineInputStream users;
  163.     try
  164.         users = new LineInputStream(new FileInputStream(root+
  165.                                 "/etc/users"));
  166.     catch(FileNotFoundException e)
  167.         throw new BadUserException(root+"/etc/users file not found");
  168.     while(true) {
  169.         String line = null;
  170.         try line = users.gets();
  171.         catch(IOException e)
  172.             throw new BadUserException("User not found");
  173.         JFSuser u;
  174.         try u = new JFSuser(line);
  175.         catch(IOException e)
  176.             throw new BadUserException("Error reading user : "+
  177.                            e.getMessage());
  178.         if (u.name.equals(name)) {
  179.             try users.close();
  180.             catch(IOException e);
  181.             return u;
  182.             }
  183.         }
  184.     }
  185.  
  186.     // getfile
  187.     // Reads and returns the contents of a named file and version.
  188.     // If start and end are not -1, then only part of the file gets read.
  189.     // If version is 0, then assume this is a single-version file
  190.     static synchronized byte []getfile(String f, int ver, int st, int en)
  191.         throws BadPathException
  192.     {
  193.     db.puts("getfile("+f+","+ver+","+st+","+en+")");
  194.     String full = root+simplify(f);
  195.     if (ver > 0)
  196.         full += ","+String.valueOf(ver);
  197.     File fl = new File(full);
  198.     LineInputStream fis;
  199.     try
  200.         fis = new LineInputStream(new FileInputStream(fl));
  201.     catch(FileNotFoundException e)
  202.         throw new BadPathException("Couldn't open file "+full);
  203.     if (st == -1) {
  204.         st = 0;
  205.         en = ((int)fl.length())-1;
  206.         }
  207.     else if (en >= fl.length())
  208.         en = ((int)fl.length())-1;
  209.     byte data[] = new byte[en-st+1];
  210.     try {
  211.         fis.skip(st);
  212.         fis.read(data, 0, data.length);
  213.         }
  214.     catch(IOException e)
  215.         throw new BadPathException("Error reading "+full);
  216.     try fis.close();
  217.     catch(IOException e);
  218.     return data;
  219.     }
  220.  
  221.     // putfile
  222.     // Saves the given data under the given file and version name, and
  223.     // marked as created by the given user.
  224.     // If no file of this name exists, a new directory entry is created.
  225.     // If the file exists but this is a new version, then a new version
  226.     //  entry is created.
  227.     // If the file and version both exists, then that version is
  228.     //  overwritten.
  229.     // If the version given is non-zero then the file is saved with
  230.     //  that version number.
  231.     // If the version is 0, and this is a new file then it is considered
  232.     //  to be a single-version file.
  233.     // If the version is 0 and this is an existing file, then a new version
  234.     //  > any existing ones is created.
  235.     static synchronized void putfile(String f, int ver, byte data[],
  236.                      String user, String type)
  237.         throws BadPathException
  238.     {
  239.     // Find out about existing file
  240.     db.puts("putfile("+f+","+ver+","+user+","+type+")");
  241.     String sim = simplify(f);
  242.     String base = sim.substring(sim.lastIndexOf('/')+1);
  243.     JFSfile oldfileinfo = null;
  244.     try oldfileinfo = statfile(sim);
  245.     catch(BadPathException e);
  246.     if (oldfileinfo != null && oldfileinfo.type.equals("jfs/directory"))
  247.         throw new BadPathException("Is a directory");
  248.     String par = parent(sim);
  249.     JFSdirectory pardir = getdir(par);
  250.     JFSfile oldfile = pardir.find(base);
  251.  
  252.     // Create user and version structures for the new file
  253.     JFSversion nvr = new JFSversion();
  254.     nvr.creator = user;
  255.     nvr.time = System.currentTimeMillis();
  256.     nvr.size = data.length;
  257.  
  258.     // Add the new file to the directory
  259.     String filename = null;
  260.     if (oldfile == null) {
  261.         // totally new file
  262.         JFSfile nfl = new JFSfile();
  263.         nfl.name = base;
  264.         nfl.type = type;
  265.         nfl.multiversion = ver==0 ? false : true;
  266.         nvr.number = nfl.multiversion ? ver : 1;
  267.         nfl.versions.addElement(nvr);
  268.         if (!user.equals("root")) {
  269.             JFSfileuser nfu = new JFSfileuser();
  270.             nfu.name = user;
  271.             nfu.rwp = "rwp";
  272.             nfl.users.addElement(nfu);
  273.             }
  274.         pardir.add(nfl);
  275.         filename = sim + (nfl.multiversion ? ","+nvr.number : "");
  276.         if (nfl.multiversion) updatelink(nfl, sim);
  277.         }
  278.     else if (!oldfile.multiversion) {
  279.         // A single-version file with this name already exists
  280.         String delname = par+"/"+oldfile.name;
  281.         try deletefile(root+"/"+delname);
  282.         catch(BadPathException e)
  283.             ;    // doesn't matter if it fails
  284.         pardir.delete(oldfile);
  285.         JFSfile nfl = new JFSfile();
  286.         nfl.name = base;
  287.         nfl.type = type;
  288.         nfl.multiversion = ver==0 ? false : true;
  289.         nvr.number = nfl.multiversion ? ver : 1;
  290.         nfl.versions.addElement(nvr);
  291.         nfl.users = oldfile.users;
  292.         pardir.add(nfl);
  293.         filename = sim + (nfl.multiversion ? ","+nvr.number : "");
  294.         }
  295.     else {
  296.         // A multi-version file with this name already exists
  297.         int verpos = oldfile.versions.size();    // position in array
  298.         if (ver != 0) {
  299.             // find this version number (if it exists)
  300.             for(int i=0; i<oldfile.versions.size(); i++)
  301.                 if (((JFSversion)oldfile.versions.elementAt(i)).
  302.                     number == ver) {
  303.                     verpos = i;
  304.                     break;
  305.                     }
  306.             }
  307.         else {
  308.             // find the highest version so far
  309.             int max = 0;
  310.             for(int i=0; i<oldfile.versions.size(); i++) {
  311.                 int n = ((JFSversion)oldfile.versions.
  312.                      elementAt(i)).number;
  313.                 if (n > max)
  314.                     max = n;
  315.                 }
  316.             ver = max+1;
  317.             }
  318.         nvr.number = ver;
  319.         if (verpos == oldfile.versions.size())
  320.             oldfile.versions.addElement(nvr);
  321.         else
  322.             oldfile.versions.setElementAt(nvr, verpos);
  323.         filename = sim + "," + ver;
  324.         updatelink(oldfile,sim);
  325.         }
  326.  
  327.     // Store data into file
  328.     LineOutputStream outfile = null;
  329.     try outfile = new LineOutputStream(
  330.             new FileOutputStream(root+filename));
  331.     catch(IOException e)
  332.         throw new BadPathException("Couldn't create file "+
  333.                        root+filename);
  334.     try {
  335.         outfile.write(data);
  336.         outfile.close();
  337.         }
  338.     catch(IOException e)
  339.         throw new BadPathException("Error writing to file "+
  340.                        root+filename);
  341.  
  342.     // Write out directory
  343.     putdir(pardir, par);
  344.     }
  345.  
  346.     // putdir
  347.     // Write out a JFSdirectory structure to a .jfs file
  348.     static synchronized void putdir(JFSdirectory d, String n)
  349.         throws BadPathException
  350.     {
  351.     db.puts("putdir("+n+")");
  352.     String full = root+simplify(n)+"/.jfs";
  353.     LineOutputStream outdir = null;
  354.     try outdir = new LineOutputStream(new FileOutputStream(full));
  355.     catch(IOException e)
  356.         throw new BadPathException("Couldn't create .jfs file "+full);
  357.     try {
  358.         d.output(outdir);
  359.         outdir.close();
  360.         }
  361.     catch(IOException e)
  362.         throw new BadPathException("Error writing .jfs file "+full);
  363.     }
  364.  
  365.     // deletefile
  366.     // Delete the given local file. If it is a directory, delete all the
  367.     // files in this directory first.
  368.     // BUG! - File.delete() can't delete directories
  369.     private static synchronized void deletefile(String file)
  370.         throws BadPathException
  371.     {
  372.     db.puts("deletefile("+file+")");
  373.     File fileinfo = new File(file);
  374.     if (fileinfo.isDirectory()) {
  375.         // delete everything in the directory first
  376.         String cont[] = fileinfo.list();
  377.         for(int i=0; i<cont.length; i++)
  378.             deletefile(file+"/"+cont[i]);
  379.         try Runtime.getRuntime().exec("/bin/rmdir "+file).waitFor();
  380.         catch(Exception e)
  381.             throw new BadPathException("rmdir failed");
  382.         }
  383.     else {
  384.         // Just delete the file
  385.         if (!fileinfo.delete())
  386.             throw new BadPathException("delete() failed");
  387.         }
  388.     }
  389.  
  390.     // delete
  391.     // Deletes the given file and version. If v is 0, then all versions
  392.     // of the file are deleted.
  393.     static synchronized void delete(String f, int v)
  394.         throws BadPathException
  395.     {
  396.     db.puts("delete("+f+","+v+")");
  397.     String file = simplify(f);
  398.     if (file.equals("/"))
  399.         throw new BadPathException("Cannot delete the root directory");
  400.     String par = parent(file);
  401.     JFSdirectory pardir = getdir(par);
  402.     JFSfile delfile = pardir.find(file.substring(file.lastIndexOf('/')+1));
  403.     if (delfile == null)
  404.         throw new BadPathException("File not found in parent");
  405.     if (!delfile.multiversion) {
  406.         // single version file
  407.         pardir.files.removeElement(delfile);
  408.         deletefile(root+"/"+file);
  409.         }
  410.     else if (v == 0) {
  411.         // multi-version file, delete all versions
  412.         pardir.files.removeElement(delfile);
  413.         for(int i=0; i<delfile.versions.size(); i++)
  414.             deletefile(root+"/"+file+","+
  415.                    ((JFSversion)delfile.versions.
  416.                    elementAt(i)).number);
  417.         updatelink(null, file);
  418.         }
  419.     else {
  420.         // delete only one version
  421.         JFSversion dv = null;
  422.         int i;
  423.         for(i=0; i<delfile.versions.size(); i++) {
  424.             JFSversion cv = (JFSversion)delfile.versions.
  425.                             elementAt(i);
  426.             if (cv.number == v) {
  427.                 dv = cv;
  428.                 break;
  429.                 }
  430.             }
  431.         if (dv == null)
  432.             throw new BadPathException("Version does not exist");
  433.         if (delfile.versions.size() == 1) {
  434.             // last version gone.. remove this file
  435.             pardir.files.removeElement(delfile);
  436.             updatelink(null, file);
  437.             }
  438.         else {
  439.             // remove just one version from the file
  440.             delfile.versions.removeElementAt(i);
  441.             updatelink(delfile, file);
  442.             }
  443.         deletefile(root+"/"+file+","+dv.number);
  444.         }
  445.  
  446.     // Write out directory
  447.     putdir(pardir, par);
  448.     }
  449.  
  450.     // mkdir
  451.     // Create a directory with the given name, owned by the given user
  452.     static synchronized void mkdir(String d, String user)
  453.         throws BadPathException
  454.     {
  455.     // Get parent dir info
  456.     db.puts("mkdir("+d+","+user+")");
  457.     String dir = simplify(d);
  458.     if (dir.equals("/"))
  459.         throw new BadPathException("Cannot make /");
  460.     String par = parent(dir);
  461.     JFSdirectory parinfo = null;
  462.     try parinfo = getdir(par);
  463.     catch(BadPathException e)
  464.         throw new BadPathException("Parent directory not found");
  465.  
  466.     // Add a new entry to the parent
  467.     String base = dir.substring(dir.lastIndexOf('/')+1);
  468.     if (parinfo.find(base) != null)
  469.         throw new BadPathException("File/directory already exists");
  470.     JFSfile dirinfo = new JFSfile();
  471.     dirinfo.name = base;
  472.     dirinfo.type = "jfs/directory";
  473.     dirinfo.multiversion = false;
  474.     JFSversion dirver = new JFSversion();
  475.     dirver.number = 1;
  476.     dirver.creator = user;
  477.     dirver.time = System.currentTimeMillis();
  478.     dirver.size = 0;
  479.     dirinfo.versions.addElement(dirver);
  480.     if (!user.equals("root")) {
  481.         JFSfileuser dirfu = new JFSfileuser();
  482.         dirfu.name = user;
  483.         dirfu.rwp = "rwp";
  484.         dirinfo.users.addElement(dirfu);
  485.         }
  486.     parinfo.add(dirinfo);
  487.  
  488.     // create a new local directory, and put an empty .jfs file in it
  489.     File dirfile = new File(root+"/"+dir);
  490.     if (!dirfile.mkdir())
  491.         throw new BadPathException("Failed to create local directory");
  492.     FileOutputStream dirjfs = null;
  493.     try {
  494.         dirjfs = new FileOutputStream(root+"/"+dir+"/.jfs");
  495.         dirjfs.close();
  496.         }
  497.     catch(IOException e)
  498.         throw new BadPathException("Failed to create .jfs file");
  499.  
  500.     // write out parent dir
  501.     putdir(parinfo, par);
  502.     }
  503.  
  504.     // copy
  505.     // Copy all versions of a file from the given source to the given
  506.     // destination. The new file is owned by the copying user
  507.     static synchronized void copy(String s, String d, String user)
  508.         throws BadPathException
  509.     {
  510.     // Create new directory entry
  511.     db.puts("copy("+s+","+d+","+user+")");
  512.     String src = simplify(s), dst = simplify(d);
  513.     if (src.equals(dst))
  514.         throw new BadPathException("Source and destination are "+
  515.                        "the same");
  516.     JFSfile srcinfo = statfile(src);
  517.     if (srcinfo.type.equals("jfs/directory"))
  518.         throw new BadPathException("Cannot copy directory");
  519.     String par = parent(dst);
  520.     JFSdirectory dirinfo = getdir(par);
  521.     String base = dst.substring(dst.lastIndexOf('/')+1);
  522.     JFSfile oldfile = dirinfo.find(base);
  523.     if (oldfile != null) {
  524.         if (oldfile.type.equals("jfs/directory"))
  525.             throw new BadPathException("Cannot copy to directory");
  526.         dirinfo.delete(oldfile);
  527.         }
  528.     srcinfo.name = base;
  529.     srcinfo.users.removeAllElements();
  530.     JFSfileuser fu = new JFSfileuser();
  531.     fu.name = user;
  532.     fu.rwp = "rwp";
  533.     srcinfo.users.addElement(fu);
  534.     dirinfo.add(srcinfo);
  535.  
  536.     // delete file being overwritten
  537.     try delete(dst, 0);
  538.     catch(BadPathException e);
  539.  
  540.     // copy all versions
  541.     if (!srcinfo.multiversion)
  542.         copyfile(root+"/"+src, root+"/"+dst);
  543.     else {
  544.         for(int i=0; i<srcinfo.versions.size(); i++) {
  545.             int vn = ((JFSversion)srcinfo.versions.elementAt(i)).
  546.                  number;
  547.             copyfile(root+"/"+src+","+vn, root+"/"+dst+","+vn);
  548.             }
  549.         updatelink(srcinfo, dst);
  550.         }
  551.  
  552.     // write directory entry to file
  553.     putdir(dirinfo, par);
  554.     }
  555.  
  556.     // copyfile
  557.     // Copy one file to another. Does not copy directories (yet).
  558.     private static synchronized void copyfile(String src, String dst)
  559.         throws BadPathException
  560.     {
  561.     db.puts("copyfile("+src+","+dst+")");
  562.     File srcinfo = new File(src);
  563.     if (srcinfo.isDirectory())
  564.         throw new BadPathException("Cannot copy directories");
  565.  
  566.     // open source and destination files
  567.     FileInputStream srcfile = null;
  568.     try srcfile = new FileInputStream(src);
  569.     catch(FileNotFoundException e)
  570.         throw new BadPathException("Source file not found");
  571.     FileOutputStream dstfile = null;
  572.     try dstfile = new FileOutputStream(dst);
  573.     catch(IOException e)
  574.         throw new BadPathException("Couldn't create destination file");
  575.  
  576.     // copy data until EOF
  577.     byte buf[] = new byte[1024];
  578.     while(true) {
  579.         int rd = 0;
  580.         try rd = srcfile.read(buf);
  581.         catch(IOException e)
  582.             throw new BadPathException("Error reading data");
  583.         if (rd < 0) break;        // End of file
  584.         try dstfile.write(buf, 0, rd);
  585.         catch(IOException e)
  586.             throw new BadPathException("Error writing data");
  587.         }
  588.     try {
  589.         srcfile.close();
  590.         dstfile.close();
  591.         }
  592.     catch(IOException e);
  593.     }
  594.  
  595.     // getgroup
  596.     // Returns a vector containing the names of all users who belong
  597.     // to the given group.
  598.     public static synchronized Vector getgroup(String group)
  599.         throws BadGroupException
  600.     {
  601.     db.puts("getgroup("+group+")");
  602.     LineInputStream uf = null;
  603.     try uf = new LineInputStream(new FileInputStream(root+"/etc/users"));
  604.     catch(IOException e)
  605.         throw new BadGroupException("Error opening users file");
  606.     Vector uv = new Vector();
  607.     while(true) {
  608.         String line = null;
  609.         try line = uf.gets();
  610.         catch(IOException e) break;
  611.         JFSuser u = null;
  612.         try u = new JFSuser(line);
  613.         catch(IOException e)
  614.             throw new BadGroupException("Users file format error");
  615.         if (u.ingroup(group))
  616.             uv.addElement(u.name);
  617.         }
  618.     try uf.close();
  619.     catch(IOException e);
  620.     return uv;
  621.     }
  622.  
  623.     // chmod
  624.     // Set or remove the access permissions for a user/group to a file.
  625.     // If perms is non-null, then it gives the new permissions string
  626.     // for the given user to the given file (overwriting any existing
  627.     // permissions)
  628.     // If perms is null, then permissions for that user to the file
  629.     // are removed.
  630.     public static synchronized void chmod(String f, String user, String p)
  631.         throws BadPathException
  632.     {
  633.     db.puts("addfileuser("+f+","+user+","+p+")");
  634.     String file = simplify(f);
  635.     if (file.equals("/"))
  636.         throw new BadPathException("Cannot change permissions of /");
  637.     String par = parent(f);
  638.     JFSdirectory parinfo = getdir(par);
  639.     JFSfile fileinfo = parinfo.find(f.substring(f.lastIndexOf('/')+1));
  640.     if (fileinfo == null)
  641.         throw new BadPathException("File not found");
  642.     for(int i=0; i<fileinfo.users.size(); i++) {
  643.         JFSfileuser fu = (JFSfileuser)fileinfo.users.elementAt(i);
  644.         if (fu.name.equals(user)) {
  645.             fileinfo.users.removeElement(fu);
  646.             break;
  647.             }
  648.         }
  649.     if (p != null) {
  650.         for(int j=0; j<p.length(); j++) {
  651.             char c = p.charAt(j);
  652.             if (c != 'r' && c != 'w' && c != 'p')
  653.                 throw new BadPathException("Bogus permissions "+
  654.                                "string");
  655.             }
  656.         JFSfileuser fu = new JFSfileuser();
  657.         fu.name = user;
  658.         fu.rwp = p;
  659.         fileinfo.users.addElement(fu);
  660.         }
  661.     putdir(parinfo, par);
  662.     }
  663.  
  664.     // rename
  665.     // Rename all versions of a file to a name new, possibly in a
  666.     // totally different directory.
  667.     static synchronized void rename(String s, String d, String user)
  668.         throws BadPathException
  669.     {
  670.     db.puts("rename("+s+","+d+","+user+")");
  671.  
  672.     // call copy and delete to do most of the work
  673.     copy(s, d, user);
  674.     delete(s, 0);
  675.     }
  676.  
  677.     // putinfo
  678.     // Store a directory entry for a file
  679.     static synchronized  void putinfo(String f, JFSfile i)
  680.         throws BadPathException
  681.     {
  682.     String file = simplify(f);
  683.     if (file.equals("/"))
  684.         throw new BadPathException("Cannot change type of /");
  685.     String par = parent(f);
  686.     JFSdirectory parinfo = getdir(par);
  687.     parinfo.replace(i);
  688.     putdir(parinfo, par);
  689.     }
  690.  
  691.     // updatelink
  692.     // For multi-version file stored in the local filesystem as foo,N
  693.     // there should be a symlink from foo to the latest version.
  694.     // updatelink() removes any existing link, and if f is non-null
  695.     // creates the symlink pointing to the latest version.
  696.     // Should be called by the put, delete, copy and rename calls
  697.     static private synchronized void updatelink(JFSfile f, String p)
  698.         throws BadPathException
  699.     {
  700.     db.puts("updatelink("+p+")");
  701.     String path = root+simplify(p);
  702.     try Runtime.getRuntime().exec("/bin/rm "+path).waitFor();
  703.     catch(Exception e);
  704.     if (f == null)
  705.         return;    // nothing more to do
  706.     int max = 0;
  707.     for(int i=0; i<f.versions.size(); i++)
  708.         max=Math.max(max, ((JFSversion)f.versions.elementAt(i)).number);
  709.     String base = path.substring(path.lastIndexOf('/')+1);
  710.     try Runtime.getRuntime().exec("/bin/ln -s "+base+","+max+" "+path);
  711.     catch(Exception e)
  712.         throw new BadPathException("ln failed");
  713.     }
  714.  
  715. }
  716.  
  717.  
  718. // BadPathException
  719. // A directory does not exist or is not part of the filesystem
  720. class BadPathException extends Exception
  721. {
  722.     BadPathException() { }
  723.     BadPathException(String why)
  724.     {
  725.     super(why);
  726.     }
  727. }
  728.  
  729. // BadUserException
  730. // A user does not exist or has a bogus name
  731. class BadUserException extends Exception
  732. {
  733.     BadUserException() { }
  734.     BadUserException(String why) { super(why); }
  735. }
  736.  
  737. // BadGroupException
  738. // A group does not exist or has a bogus name
  739. class BadGroupException extends Exception
  740. {
  741.     BadGroupException() { }
  742.     BadGroupException(String why) { super(why); }
  743. }
  744.  
  745. // NullOutputStream
  746. // An output stream that goes nowhere
  747. class NullOutputStream extends LineOutputStream
  748. {
  749.     public void write(int b) { }
  750.     public void write(byte b[]) { }
  751.     public void write(byte b[], int off, int len) { }
  752.     public void flush() { }
  753.     public void close() { }
  754. }
  755.  
  756.